/*
 * Created on 2005/4/3
 *
 */
package cliente.applet;

import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Panel;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.image.ImageObserver;
import java.rmi.RemoteException;
import java.util.ArrayList;

import javax.swing.JDialog;

import comum.Localizacao;

/**
 * @author Lin Yu Ching
 *  
 */
public class PanelMapa extends Panel {

    JanelaApp app;
    MapaCanvas canvas;

    public PanelMapa(JanelaApp _app) {
        app = _app;
        setLayout(new BorderLayout());
        //		Panel grid = new Panel();
        //		grid.setLayout(new GridLayout(0, 2));
        //		add("Center", grid);
        if (app.getDocumentBase() == null) {
            System.out.println("Document Base retornando null!!!");
        } else {
            System.out.println(app.getDocumentBase());
        }
        //		Image imgMapa = app.getImage(app.getDocumentBase(),
        //				"cliente/applet/TERREO.JPG");
        //		grid.add(canvas = new MapaCanvas(app, imgMapa));
        //		add(canvas = new MapaCanvas(app, imgMapa));
        add(canvas = new MapaCanvas(app));
        setBounds(25, 0, JanelaApp.APP_W, JanelaApp.APP_H - 25);
    }

    public MapaCanvas getCanvas() {
        return canvas;
    }

}

class MapaCanvas extends Canvas implements ImageObserver, MouseListener, MouseMotionListener, Runnable {

    private volatile Thread timer;
    private int contadorBolaAtual = 0;
    private int contadorFreqChamadaFunc = 0;

    JanelaApp app;
    Image img;
    
    double hmult = 0.8;
    int xprev = 0;
    int yprev = 0;
    int xpos = 0;
    int ypos = 0;

    boolean isCentralizacaoAutomatica = true;

    int tipoRetricao = 0;
    Localizacao rotaTotal[] = null;
    ArrayList rota = null;
    Localizacao localizacaoAtual = null;
    Localizacao localizacaoFinal = null;
    double raioTeste;
    /*
     * Criterio: se a distancia passou de 1.5 vezes da distancia entre o ponto
     * atual e o primeio ponto da rota TODO: melhor aproveitar os pontos
     * calculados
     */
    final double fatorRaioTeste = 0.75;
    final double limitePertoFinal = 30;
    int indiceProximaLocalizacao;
    int indiceQMudaAndar;
    int andarAtualDoMapa;
    int flagAnimacao = 0;

    public MapaCanvas(JanelaApp _app) {
        app = _app;
        //		img = _img;
        //		img.flush();
        setBounds(0, 0, 240, 295);
        addMouseListener(this);
        addMouseMotionListener(this);

        localizacaoFinal = app.getLocalizacaoFinal();
        tipoRetricao = app.getTipoRetricao();

        pegaLocalizacaoEAvaliaRota();

        timer = new Thread(this);
        timer.start();
    }

    public void mouseClicked(MouseEvent e) {
        //		System.out.println("clicou no mapa posicao: " + e.getX() + " , " +
        // e.getY());
    }

    public void mouseEntered(MouseEvent e) {
        requestFocus();
        e.consume();
    }

    public void mouseExited(MouseEvent e) {
    }

    public void mousePressed(MouseEvent e) {
        xprev = e.getX();
        yprev = e.getY();
        //		System.out.println("precionou no mapa posicao: " + e.getX() + " , " +
        // e.getY());
        //		System.out.println("ImgWidth=" + img.getWidth(app) + " ImgHeight=" +
        // img.getHeight(app) );
        e.consume();
    }

    public void mouseReleased(MouseEvent e) {
        e.consume();
    }

    public void mouseDragged(MouseEvent e) {
        int xMouse = e.getX();
        int yMouse = e.getY();

        if (!isCentralizacaoAutomatica) {
            xpos += xMouse - xprev;
            ypos += yMouse - yprev;
            ajustaXPosYPos();
        }

        xprev = xMouse;
        yprev = yMouse;
        //		System.out.println("posicao (" + xpos + ", " + ypos + ")");
        e.consume();
    }

    public void mouseMoved(MouseEvent e) {
    }

    public void paint(Graphics g) {
        if (flagAnimacao == 0) {
            //		System.out.println("move ->, -> = " + xpos + " , " + ypos);
            g.drawImage(img, xpos, ypos, (int) (img.getWidth(this) * hmult), (int) (img.getHeight(this) * hmult), this);
            g.setColor(Color.red);

            for (int i = 0; i < rota.size() - 1; i++) {
                g.drawLine((int) (((Localizacao) rota.get(i)).getX() * hmult + xpos),
                        (int) (((Localizacao) rota.get(i)).getY() * hmult + ypos), (int) (((Localizacao) rota
                                .get(i + 1)).getX()
                                * hmult + xpos), (int) (((Localizacao) rota.get(i + 1)).getY() * hmult + ypos));
            }
            g.setColor(Color.orange);
            int raio = contadorBolaAtual * 3;
            g.drawOval((int) (localizacaoAtual.getX() * hmult + xpos) - raio,
                    (int) (localizacaoAtual.getY() * hmult + ypos) - raio, raio * 2, raio * 2);
        } else {
            if (flagAnimacao == 1) {
                System.out.println("[cliente] subir!!");
                g.drawString("Va para o andar superior", 50, 100);
            } else if (flagAnimacao == -1){
                System.out.println("[cliente] descer!!");
                g.drawString("Va para o andar inferior", 50, 100);
            } else {
                System.out.println("[cliente] chegou ao destino!!");
                g.drawString("Voce chegou!!!", 50, 100);
            }
            
        }
    }

    public void ampliar() {
        hmult *= 1.2;
        ajustaXPosYPos();
    }

    public void diminuir() {
        hmult /= 1.2;
        ajustaXPosYPos();
    }

    public void alteraCentralizacaoAutomatica() {
        isCentralizacaoAutomatica = !isCentralizacaoAutomatica;
    }

    private void ajustaXPosYPos() {
        int xLimiteMax = img.getWidth(app) * hmult > getBounds().width ? 0 : (int) (getBounds().width - img
                .getWidth(app)
                * hmult);
        int xLimiteMin = img.getWidth(app) * hmult > getBounds().width ? (int) (getBounds().width - img.getWidth(app)
                * hmult) : 0;
        int yLimiteMax = img.getHeight(app) * hmult > getBounds().height ? 0 : (int) (getBounds().height - img
                .getHeight(app)
                * hmult);
        int yLimiteMin = img.getHeight(app) * hmult > getBounds().height ? (int) (getBounds().height - img
                .getHeight(app)
                * hmult) : 0;

        if (xpos > xLimiteMax)
            xpos = xLimiteMax;
        if (xpos < xLimiteMin)
            xpos = xLimiteMin;
        if (ypos > yLimiteMax)
            ypos = yLimiteMax;
        if (ypos < yLimiteMin)
            ypos = yLimiteMin;

        repaint();
    }

    private void pegaLocalizacaoEAvaliaRota() {

        boolean bGeraNovaRota = false;

        try {
            localizacaoAtual = app.getServidor().obtemLocalizacao();

            //    		if (img != null) {
            //        		img.flush();
            //    		}

            if (localizacaoAtual.getAndar() == andarAtualDoMapa) {
                img = app.getImage(app.getDocumentBase(), "cliente/applet/Andar" + localizacaoAtual.getAndar() + ".JPG");
            } else {
                flagAnimacao = 0;
            }

            if (isCentralizacaoAutomatica && flagAnimacao == 0) {
                xpos = app.getWidth() / 2 - (int) (localizacaoAtual.getX() * hmult);
                ypos = app.getHeight() / 2 - (int) (localizacaoAtual.getY() * hmult);
                ajustaXPosYPos();
            }

        } catch (RemoteException re) {
            System.out.println("Nao pegou localizacao atual,\n\t" + re.getMessage());
            re.printStackTrace();
        }

        if (flagAnimacao == 0) {
            if (rota == null) { // iniciacao
                bGeraNovaRota = true;
            } else {
                if (localizacaoAtual.distancia((Localizacao) rota.get(indiceProximaLocalizacao - 1)) > raioTeste) {
                    if (indiceProximaLocalizacao == rota.size() - 1) {
                        if (localizacaoAtual.distancia((Localizacao) rota.get(rota.size() - 1)) < limitePertoFinal) {
                            if (indiceQMudaAndar >= rotaTotal.length) {
                                System.out.println("[cliente] acho que esta muito perto do destino...");
                                flagAnimacao = 2;
                            } else {
                                System.out.println("[cliente] manda o cara subir ou descer!!");
                                flagAnimacao = rotaTotal[indiceQMudaAndar].getAndar()
                                        - rotaTotal[indiceQMudaAndar - 1].getAndar();
                                int andarAtual = rotaTotal[indiceQMudaAndar].getAndar();
                                rota = new ArrayList();
                                for (; indiceQMudaAndar < rotaTotal.length
                                        && rotaTotal[indiceQMudaAndar].getAndar() == andarAtual; indiceQMudaAndar++) {
                                    rota.add(rotaTotal[indiceQMudaAndar]);
                                }
                            }
                        } else {
                            System.out.println("[cliente] acho que esta +/- perto do destino...");
                        }
                    } else {
                        indiceProximaLocalizacao++;
                        raioTeste = fatorRaioTeste
                                * ((Localizacao) rota.get(indiceProximaLocalizacao - 1)).distancia((Localizacao) rota
                                        .get(indiceProximaLocalizacao));
                        if (localizacaoAtual.distancia((Localizacao) rota.get(indiceProximaLocalizacao - 1)) > raioTeste) {
                            System.out.println("[cliente] acho que saiu da rota...");
                            bGeraNovaRota = true;
                        } else {
                            System.out.println("[cliente] bom!! seguiu a rota...");
                        }
                    }
                }
            }

            if (bGeraNovaRota) {
                try {
                    rotaTotal = app.getServidor().geraRota(localizacaoAtual, localizacaoFinal, tipoRetricao);
                    andarAtualDoMapa = rotaTotal[0].getAndar();
                    rota = new ArrayList();
                    for (indiceQMudaAndar = 1; indiceQMudaAndar < rotaTotal.length
                            && rotaTotal[indiceQMudaAndar].getAndar() == andarAtualDoMapa; indiceQMudaAndar++) {
                        rota.add(rotaTotal[indiceQMudaAndar]);
                        System.out.println("Localizacao ( " + indiceQMudaAndar + " ): " + rotaTotal[indiceQMudaAndar]);
                    }
                } catch (RemoteException re) {
                    System.out.println("Nao gerou nova rota,\n\t" + re.getMessage());
                    re.printStackTrace();
                }
                if (rota.size() > 0) {
                    indiceProximaLocalizacao = 1;
                } else {
                    System.out.println("[cliente] ouuui, voce esta no destino jah...");
                }
                raioTeste = fatorRaioTeste
                        * ((Localizacao) rota.get(indiceProximaLocalizacao - 1)).distancia((Localizacao) rota
                                .get(indiceProximaLocalizacao));
                System.out.println("[cliente] vamos desde inicio...");
            }

        }

        //		System.out.println("[cliente::pegaLocalizacaoEAvaliaRota] indice=" +
        // indiceProximaLocalizacao + " raioTeste=" + raioTeste);

    }

    public void run() {

        final int freqRefresh = 12;
        final int freqChamadaFunc = 4;
        Thread me = Thread.currentThread();
        while (timer == me) {
            try {
                Thread.sleep(1000 / freqRefresh);
            } catch (InterruptedException e) {
            }
            contadorBolaAtual = ++contadorBolaAtual % 15;
            //TODO: implementar chamada periodica de funcao aqui
            contadorFreqChamadaFunc = ++contadorFreqChamadaFunc % (freqRefresh / freqChamadaFunc);
            if (contadorFreqChamadaFunc == 0) {

                pegaLocalizacaoEAvaliaRota();
            }
            repaint();
        }
    }

    public boolean isCentralizacaoAutomatica() {
        return isCentralizacaoAutomatica;
    }

}